package devcken.hibernate.query;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 데이터 목록의 페이지 구분을 위한 지시자로 데이터 목록마다 1페이지 당 목록 개수(페이지 크기), 현재 페이지 등을 관리한다.
 * @author Devcken
 */
public class PaginationDirector
{
	private final static Logger logger = LoggerFactory.getLogger(PaginationDirector.class);
	
	/**
	 * 데이터 목록 구분을 위해 사용되는 key의 접두사를 나타낸다.
	 */
	private final String _PREFIX = "PAGINATION_";
	
	/**
	 * 페이지 크기 구분을 위해 사용되는 key의 접미사를 나타낸다.
	 */
	private final String _PAGE_SIZE_SUFFIX = "_PAGE_SIZE";
	
	/**
	 * 페이지 구분을 위해 사용되는 key의 접미사를 나타낸다.
	 */
	private final String _PAGE_SUFFIX = "_PAGE";
	
	/**
	 * 1페이지 당 기본 목록 개수(설정값이 없을 경우 사용)을 나타낸다.
	 */
	private final Integer _DEFAULT_SIZE = 20;
	
	/**
	 * 페이지 목록 크기에 대한 맵을 나타낸다.
	 */
	private Map<String, Integer> _pagesSizes;
	
	/**
	 * 주어진 키에 대한 페이지 당 목록 크기를 가져온다.
	 * @param request HTTP 요청을 설정한다.
	 * @param key 페이지 당 목록 크기에 대한 키를 설정한다.
	 * @return 주어진 키에 해당하는 페이지 당 목록 크기를 반환한다.
	 */
	public Integer getPageSize(HttpServletRequest request, String key)
	{
		return this.getPageSize(request, key, _DEFAULT_SIZE);
	}
	
	/**
	 * 주어진 키에 대한 페이지 크기를 가져온다. 만약, 주어진 키에 대한 페이지 크기가 없다면 주어진 페이지 크기를 이용한다.
	 * @param request HTTP 요청을 설정한다.
	 * @param key 페이지 당 목록 크기에 대한 키를 설정한다.
	 * @param defaultSize 페이지 당 기본 목록 크기를 설정한다. 키에 대한 페이지 목록 크기가 존재하지 않는 경우 대신 사용된다.
	 * @return 주어진 키에 해당하는 페이지 당 목록 크기를 반환한다.
	 */
	public Integer getPageSize(HttpServletRequest request, String key, Integer defaultSize)
	{
		HttpSession session = request.getSession();
		
		try
		{
			key = this.mixPageSizeKey(key);
			
			if (session.getAttribute(key) == null)
			{
				// 페이지 크기 목록에 해당 키가 존재하지 않는다면, 주어진 크기로 키를 등록한다.
				if (this._pagesSizes.containsKey(key))
				{
					session.setAttribute(key, this._pagesSizes.get(key));
				}
				else
				{
					// 파라메터로 넘어온 크기가 0이거나 그보다 작으면 기본 크기를 이용한다. 
					if (defaultSize <= 0)
					{
						defaultSize = _DEFAULT_SIZE;
					}
					
					session.setAttribute(key, defaultSize);
				}
			}
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return (Integer)session.getAttribute(key);
	}
	
	/**
	 * 주어진 키에 대한 페이지 크기를 설정한다.
	 * @param request HTTP 요청을 설정한다.
	 * @param key 페이지 당 목록 크기에 대한 키를 설정한다.
	 * @param size 설정하고자 하는 페이지 목록 크기를 설정한다.
	 */
	public void setPageSize(HttpServletRequest request, String key, Integer size)
	{
		try
		{
			key = this.mixPageSizeKey(key);
			
			HttpSession session = request.getSession();
			
			session.setAttribute(key, size);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
	}
	
	/**
	 * 페이지 크기 키(클래스 내부 사용)를 구성한다.
	 * @param key 페이지 당 목록 크기에 대한 키를 설정한다.
	 * @return 내부적으로 사용되는 목록 크기 키를 반환한다.
	 */
	private String mixPageSizeKey(String key)
	{
		return _PREFIX + key + _PAGE_SIZE_SUFFIX;
	}
	
	/**
	 * 주어진 키에 대한 페이지 번호를 가져온다.
	 * @param request HTTP 요청을 설정한다.
	 * @param key 페이지 번호에 대한 키를 설정한다.
	 * @return 주어진 키에 대한 페이지 번호를 반환한다.
	 */
	public Integer getPage(HttpServletRequest request, String key)
	{
		HttpSession session = request.getSession();
		
		try
		{
			key = mixPageKey(key);
			
			// 키가 존재하지 않는 경우, 1 페이지로 설정한다.
			if (session.getAttribute(key) == null)
			{
				session.setAttribute(key, 1);
			}
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
		
		return (Integer)session.getAttribute(key);
	}
	
	/**
	 * 주어진 키에 대한 페이지 번호를 설정한다.
	 * @param request HTTP 요청을 설정한다.
	 * @param key 페이지 번호에 대한 키를 설정한다.
	 * @param value 페이지 번호를 설정한다.
	 */
	public void setPage(HttpServletRequest request, String key, Integer pageNo)
	{
		try
		{
			key = mixPageKey(key);
			
			HttpSession session = request.getSession();
			
			session.setAttribute(key, pageNo);
		}
		catch (Exception error)
		{
			logger.error(error.getMessage(), error);
		}
	}
	
	/**
	 * 페이지 번호 키를 구성한다.
	 * @param key 페이지 번호에 대한 키를 설정한다.
	 * @return 내부적으로 사용되는 페이지 번호 키를 반환한다.
	 */
	private String mixPageKey(String key)
	{
		return _PREFIX + key + _PAGE_SUFFIX;
	}
	
	public void setDefaultSizes(Map<String, Integer> list)
	{
		this._pagesSizes = list;
	}
}